// TCP文件传输客户端
#include "_public.h"

struct st_arg{
	int clienttype;		// 客户端类型，1-上传文件，2-下载文件
	char ip[31];
	int port;
	int ptype;			// 文件上传成功后文件的处理方式，1-删除文件，2-移动到备份目录
	char clientpath[301];
	char clientpathbak[301];
	bool andchild;		// 是否上传clientpath目录下各级子目录的文件
	char matchname[301];// 待上传文件名的匹配规则
	char srvpath[301];
	int timetvl;		// 扫描本地目录文件的时间间隔
	int timeout;		// 进程心跳的超时时间
	char pname[51];		// 进程名
} starg;

CLogFile logfile;
CPActive PActive;
CTcpClient TcpClient;
void EXIT(int sig);
void _help();
bool _xmltoarg(char *strxmlbuffer);

char strrecvbuffer[1024], strsendbuffer[1024];
bool Login(const char *argv);
bool ActiveTest();			
 
int main(int argc, char *argv[])
{
	if (argc != 3)
	{
		_help();
		return -1;
	}

	CloseIOAndSignal();
	signal(SIGINT, EXIT);
	signal(SIGTERM, EXIT);

	if (logfile.Open(argv[1], "a+") == false){
		printf("打开日志文件失败(%s)\n", argv[1]);
		return -1;
	}

	if(_xmltoarg(argv[2]) == false){
		return -1;
	}

	// PActive.AddPInfo(starg.timeout, starg.pname);

	// 向服务端发起连接请求
	if( TcpClient.ConnectToServer( starg.ip, starg.port ) == false){
		logfile.Write("TcpClient.ConnectToServer(%s, %s) failed.\n", starg.ip, starg.port);
		EXIT(-1);
	}

	if (Login(argv[2]) == false){
		logfile.Write("Login() failed.\n");
		EXIT(-1);
	}

	sleep(3);

	for (int i=3; i<5; ++i){
		if(ActiveTest() == false){
			break;
		}
		sleep(i);
	}

	EXIT(0);
}

// 心跳
bool ActiveTest(){
	memset(strsendbuffer, 0, sizeof(strsendbuffer));
	memset(strrecvbuffer, 0, sizeof(strrecvbuffer));
	SPRINTF(strsendbuffer, sizeof(strsendbuffer),"<activetest>ok</activetest>");

	if ( TcpClient.Write(strsendbuffer) == false ) // 向服务端发送请求报文。
	{
		return false;
	}
	logfile.Write("发送：%s\n", strsendbuffer);
	
	if ( TcpClient.Read(strrecvbuffer, 20) == false ) // 接收服务端的回应报文。
	{
		return false;
	}
	logfile.Write("接收：%s\n", strrecvbuffer);

	return true;
}

// 登录
bool Login(const char *argv){
	memset(strsendbuffer, 0, sizeof(strsendbuffer));
	memset(strrecvbuffer, 0, sizeof(strrecvbuffer));

	SPRINTF(strsendbuffer, sizeof(strsendbuffer),"%s<clienttype>1</clienttype>", argv);
	if ( TcpClient.Write(strsendbuffer) == false ) // 向服务端发送请求报文
	{
		return false;
	}
	logfile.Write("发送：%s\n", strsendbuffer);

	if ( TcpClient.Read(strrecvbuffer, 20) == false ) // 接收服务端的回应报文
	{
		return false;
	}
	logfile.Write("接收：%s\n", strrecvbuffer);

	logfile.Write("登录(%s:%d)成功\n", starg.ip, starg.port);
	return true;
}

void EXIT(int sig) {
	logfile.Write("程序退出，sig=%d\n\n", sig);
	exit(0);
}

void _help() {
	printf("\n");
	printf("Using:/project/tools1/bin/tcpputfiles logfilename xmlbuffer\n\n");

	printf("Sample:/project/tools1/bin/procctl 20 /project/tools1/bin/tcpputfiles /log/idc/tcpputfiles_surfdata.log \"<ip>192.168.199.128</ip><port>5005</port><ptype>1</ptype><clientpath>/tmp/tcp/surfdata1</clientpath><clientpathbak>/tmp/tcp/surfdata1bak</clientpathbak><andchild>true</andchild><matchname>*.XML,*.CSV</matchname><srvpath>/tmp/tcp/surfdata2</srvpath><timetvl>10</timetvl><timeout>50</timeout><pname>tcpputfiles_surfdata</pname>\"\n");
	printf("       /project/tools1/bin/procctl 20 /project/tools1/bin/tcpputfiles /log/idc/tcpputfiles_surfdata.log \"<ip>192.168.199.128</ip><port>5005</port><ptype>2</ptype><clientpath>/tmp/tcp/surfdata1</clientpath><clientpathbak>/tmp/tcp/surfdata1bak</clientpathbak><andchild>true</andchild><matchname>*.XML,*.CSV</matchname><srvpath>/tmp/tcp/surfdata2</srvpath><timetvl>10</timetvl><timeout>50</timeout><pname>tcpputfiles_surfdata</pname>\"\n\n\n");

	printf("本程序是数据中心的公共功能模块，采用tcp协议把文件发送给服务端。\n");
	printf("logfilename   本程序运行的日志文件。\n");
	printf("xmlbuffer     本程序运行的参数，如下：\n");
	printf("ip            服务端的IP地址。\n");
	printf("port          服务端的端口。\n");
	printf("ptype         文件上传成功后的处理方式：1-删除文件；2-移动到备份目录。\n");
	printf("clientpath    本地文件存放的根目录。\n");
	printf("clientpathbak 文件成功上传后，本地文件备份的根目录，当ptype==2时有效。\n");
	printf("andchild      是否上传clientpath目录下各级子目录的文件，true-是；false-否，缺省为false。\n");
	printf("matchname     待上传文件名的匹配规则，如\"*.TXT,*.XML\"\n");
	printf("srvpath       服务端文件存放的根目录。\n");
	printf("timetvl       扫描本地目录文件的时间间隔，单位：秒，取值在1-30之间。\n");
	printf("timeout       本程序的超时时间，单位：秒，视文件大小和网络带宽而定，建议设置50以上。\n");
	printf("pname         进程名，尽可能采用易懂的、与其它进程不同的名称，方便故障排查。\n\n");
}

// 把xml解析到参数starg结构
bool _xmltoarg(char *strxmlbuffer) {
	memset(&starg, 0, sizeof(struct st_arg));

	GetXMLBuffer(strxmlbuffer, "ip", starg.ip);
	if (strlen(starg.ip) == 0)
	{
		logfile.Write("ip is null.\n");
		return false;
	}

	GetXMLBuffer(strxmlbuffer, "port", &starg.port);
	if (starg.port == 0)
	{
		logfile.Write("port is null.\n");
		return false;
	}

	GetXMLBuffer(strxmlbuffer, "ptype", &starg.ptype);
	if ((starg.ptype != 1) && (starg.ptype != 2))
	{
		logfile.Write("ptype not in (1,2).\n");
		return false;
	}

	GetXMLBuffer(strxmlbuffer, "clientpath", starg.clientpath);
	if (strlen(starg.clientpath) == 0)
	{
		logfile.Write("clientpath is null.\n");
		return false;
	}

	GetXMLBuffer(strxmlbuffer, "clientpathbak", starg.clientpathbak);
	if ((starg.ptype == 2) && (strlen(starg.clientpathbak) == 0))
	{
		logfile.Write("clientpathbak is null.\n");
		return false;
	}

	GetXMLBuffer(strxmlbuffer, "andchild", &starg.andchild);

	GetXMLBuffer(strxmlbuffer, "matchname", starg.matchname);
	if (strlen(starg.matchname) == 0)
	{
		logfile.Write("matchname is null.\n");
		return false;
	}

	GetXMLBuffer(strxmlbuffer, "srvpath", starg.srvpath);
	if (strlen(starg.srvpath) == 0)
	{
		logfile.Write("srvpath is null.\n");
		return false;
	}

	GetXMLBuffer(strxmlbuffer, "timetvl", &starg.timetvl);
	if (starg.timetvl == 0)
	{
		logfile.Write("timetvl is null.\n");
		return false;
	}

	// 扫描本地目录文件的时间间隔，单位：秒。
	// starg.timetvl没有必要超过30秒。
	if (starg.timetvl > 30)
		starg.timetvl = 30;

	// 进程心跳的超时时间，一定要大于starg.timetvl，没有必要小于50秒。
	GetXMLBuffer(strxmlbuffer, "timeout", &starg.timeout);
	if (starg.timeout == 0)
	{
		logfile.Write("timeout is null.\n");
		return false;
	}
	if (starg.timeout < 50)
		starg.timeout = 50;

	GetXMLBuffer(strxmlbuffer, "pname", starg.pname, 50);
	if (strlen(starg.pname) == 0)
	{
		logfile.Write("pname is null.\n");
		return false;
	}

	return true;
}
